package com.cn.ycy.config;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfig;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import com.google.common.collect.Lists;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.web.Log4jServletContextListener;
import org.apache.logging.log4j.web.Log4jServletFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.DispatcherType;
import java.util.EnumSet;
import java.util.Set;

/**
 * @author xianglong.chen
 * @description
 * @time 2019-09-24 17:22
 */
@Configuration
public class DynamicLoggerAutoConfigure {

  private final static String ROOT_LOGGER_NAME = "ROOT";
  private final static String LOGGER_LEVEL_TAG = "logging.level.";
  private final Logger logger = LoggerFactory.getLogger(getClass());

  @ApolloConfig
  private Config config;

  @ApolloConfigChangeListener
  private void configChangeListter(ConfigChangeEvent changeEvent) {
    if (config == null) {
      logger.warn("the ucm2 config is null ,ignore change logger level!");
      return;
    }

    Set<String> keys = changeEvent.changedKeys();
    for (String key : keys) {
      if (key.contains(LOGGER_LEVEL_TAG)) {
        String strLevel = config.getProperty(key, "INFO");
        Level level = Level.getLevel(strLevel.toUpperCase());
        if (level == null) {
          level = Level.INFO;
          logger.warn("the config of log4j2 level({}) is error,so provided the info level!", strLevel);
        }
        String loggerName = key.replace(LOGGER_LEVEL_TAG, "");
        logger.info("change logger level {}:{}", key, level.name());
        Configurator.setLevel(loggerName.equalsIgnoreCase(ROOT_LOGGER_NAME) ? LogManager.ROOT_LOGGER_NAME : loggerName, level);
      }
    }
  }

  @Bean
  public FilterRegistrationBean filterRegistrationBean() {
    FilterRegistrationBean filter = new FilterRegistrationBean(new Log4jServletFilter());
    filter.setUrlPatterns(Lists.newArrayList("/*"));
    filter.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
    filter.setMatchAfter(false);
    filter.setAsyncSupported(true);
    return filter;
  }

  @Bean
  public ServletListenerRegistrationBean slistener() {
    return new ServletListenerRegistrationBean(new Log4jServletContextListener());
  }

}
